package edu.ucsd.ccdb.tagPopup;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.concurrent.ExecutionException;

import javax.swing.AbstractAction;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.text.BadLocationException;
import org.jdesktop.swingworker.SwingWorker;

import edu.ucsd.ccdb.MainConfiguration;
import edu.ucsd.ccdb.servlet.ServletSendReceive;
import edu.ucsd.ccdb.tagPopup.dataType.NIFOntologyTerm;
import edu.ucsd.ccdb.tagPopup.util.DetailViewAutoRefresh;
import edu.ucsd.ccdb.tagPopup.util.SummaryPaneRefresher;
import edu.ucsd.irods.IRODSFileString;
import edu.ucsd.irods.SQLDBQuery;

public class OnthoTab extends JPanel implements DocumentListener, ListSelectionListener, ActionListener  {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private static enum Mode {INSERT, AUTOCOMPLETE, MOUSECOMPLETE};
	private static final String COMMIT_ACTION = "commit";
	private Mode mode; 
	
//	String[] petStrings = { "bird", "cat", "dog", "rabbit", "pig" };
	
	private JTextField typingField ;
	private JList suggestField;
	private  DefaultListModel listModel;
	
	// data
	private String username;
	private Integer MPID;
	private IRODSFileString file;
	private JPanel summaryPane;
	private JDialog parent;
	
	private JPanel detailView;
	private JFrame mainFrame;
	private String baseFolder;
	private List<String> clickedFile;
	
	
	
	public OnthoTab ( JPanel detailView, JFrame mainFrame, String baseFolder, List<String> clickedFile,
						String username, Integer MPID, IRODSFileString file, JPanel summaryPane, JDialog parent) {
		
		this.username = username;
		this.MPID = MPID;
		this.file = file;
		this.summaryPane = summaryPane;
		this.parent = parent;
		
		this.detailView = detailView;
		this.mainFrame = mainFrame;
		this.baseFolder = baseFolder;
		this.clickedFile = clickedFile;
		
		mode = Mode.INSERT;
		listModel = new DefaultListModel();
		
		typingField = new JTextField(5);
		suggestField = new JList(listModel);
		
		JButton button = new JButton ("Add tag");
		button.setAlignmentX(CENTER_ALIGNMENT);
		
		// ------------Add action listener to button---------
		button.addActionListener(this);
		
		//-------------SETTING UP THE TYPYING FIELD-----------
		// add typing field attributes
		typingField.getDocument().addDocumentListener(this);
		// set keymap for the typing Field
		
//		InputMap im = typingField.getInputMap();
//		ActionMap am = typingField.getActionMap();
//		im.put(KeyStroke.getKeyStroke("ENTER"), COMMIT_ACTION);
//		am.put(COMMIT_ACTION, new CommitAction() );
		
		
		//------------SETTING UP THE SUGGEST FIELD--------------
		suggestField.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		suggestField.setLayoutOrientation(JList.VERTICAL);
		suggestField.addListSelectionListener(this);
		
		typingField.setEditable(true);
		
		// populate suggestiveField		
		setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
		add (typingField);
		add ( new JScrollPane( suggestField ) );
		add (button);
	}
	
	private void fillSuggestField ( List<NIFOntologyTerm> data ) {
		listModel.clear();
		for (NIFOntologyTerm element: data) {
//			suggestField.append(element + "\n" );
			listModel.addElement( element );
		}
	}
	
	private void fillSuggestFieldWithLoadingMessage () {
		listModel.clear();
		listModel.addElement("Loading... I know, I want to shoot myself too :D");
	}

	public void changedUpdate(DocumentEvent e) {
	}


	public void removeUpdate(DocumentEvent e) {
	}
	
	/*
	 * (non-Javadoc) Autocomplete logic. Get the suggestive term then find all the possible terms 
	 * 				 on the suggestPane 		 
	 * @see javax.swing.event.DocumentListener#insertUpdate(javax.swing.event.DocumentEvent)
	 */
	public void insertUpdate(DocumentEvent e) {
	
		// error check
		suggestField.clearSelection();
		
		if (e.getLength() != 1 ){
			return;			
		}
		
		int pos = e.getOffset();
		String content = null ;
		
		try {
			content = typingField.getText (0, pos + 1) ;
		}
		catch (BadLocationException e1 ){
			e1.printStackTrace();
		}
		
		// find where the word starts
		int w;
		for (w = pos; w >=0 ; w -- ) {
			if (! Character.isLetter(content.charAt(w))) {
				break;
			}
		}
		
		if (pos - w  <2 ) {
			return;	// too few character
		}

		String prefix = content.substring(w + 1 ).toLowerCase();
		fillSuggestFieldWithLoadingMessage();
		
		FillTableLengthyTask newTask = new FillTableLengthyTask(prefix);
		newTask.execute();
	}
	
	private class FillTableLengthyTask extends SwingWorker<List<NIFOntologyTerm>, Void > {

		String prefix;
		
		public FillTableLengthyTask (String prefix ) {
			this.prefix = prefix;
		}
		
		@Override
		protected List<NIFOntologyTerm> doInBackground() throws Exception {
			// change list to list of NIFOntologyTerm
			List<NIFOntologyTerm> list = new ArrayList<NIFOntologyTerm>();
			
			try {
//				list = NifServiceWrapper.getAutoRequestList(prefix);
				list = SQLDBQuery.getNIFTerms (prefix);

			} catch (Exception e1) {
				e1.printStackTrace();
			}
				
			return list;
		}
		
		@Override
		public void done() {
			
			try {
				List<NIFOntologyTerm> list = get();
				
				Collections.sort(list, new NIFOntologyTerm.NIFOntologyComparator()  );
				fillSuggestField ( list );
				
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			}
			mode = Mode.INSERT;
		}
	}
	
	private class CommitAction extends AbstractAction {

		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent e) {
			
			if (mode == Mode.AUTOCOMPLETE ) {
				int pos = typingField.getSelectionEnd();
//					typingField.getDocument().insertString(pos, " ", null);
				typingField.setCaretPosition(pos);
				
				mode = Mode.INSERT;
			}
			else {
				typingField.replaceSelection("\n");
			}		
			
		}
	}

	/*
	 * (non-Javadoc) for the suggestFiled when clicking on item on the list
	 * @see javax.swing.event.ListSelectionListener#valueChanged(javax.swing.event.ListSelectionEvent)
	 */
	public void valueChanged(ListSelectionEvent e) {

		if (!e.getValueIsAdjusting()) {
			JList list = (JList) e.getSource();
			
			if (!list.isSelectionEmpty()) {
				mode = Mode.MOUSECOMPLETE;
				SwingUtilities.invokeLater(new MouseChangeValue(list));
			}
		}
	}
	
	private class MouseChangeValue  implements Runnable {
		
		JList list;
		
		public MouseChangeValue( JList list) {
			this.list = list;			
		}
		
		public void run() {
			
			if (mode == Mode.MOUSECOMPLETE) {
				NIFOntologyTerm data = (NIFOntologyTerm) list.getSelectedValue();
				
				// losing focus leads to losing the selected index here
				int index = list.getSelectedIndex();
				
				typingField.setText( data.getName() );
//				typingField.setCaretPosition(typingField.getSelectionEnd());
				
				list.setSelectedIndex(index);
				mode = Mode.INSERT;
			}
		}
	}

	/*
	 * (non-Javadoc) The submit NIF term logic 
	 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	public void actionPerformed(ActionEvent e) {

		NIFOntologyTerm data = (NIFOntologyTerm) suggestField.getSelectedValue();
		
		System.out.println (data == null ? "Null" : data.toString());

		try {
		
			if (data != null) {

				SQLDBQuery.manageInsertNewTagOnthology(file.getAbsolutePath(), 
						username , MPID, data.getName(), data.getOntoURL());
				
				if ( file.isDirectory() ) {
				
					Queue<IRODSFileString> queue = new PriorityQueue<IRODSFileString>(); 
					queue.offer(file);
					
					IRODSFileString iterateFile = null;		
					while ( (iterateFile = queue.poll() ) != null ) {
					
						String query = MainConfiguration.SERVLET_SERVER + MainConfiguration.SERVLET_PARAMETER + iterateFile.getAbsolutePath();
						List<IRODSFileString> listFiles = ServletSendReceive.getResponse( query );
						
						for (IRODSFileString element: listFiles ) {
							
							if (element.isDirectory() )
								queue.offer(element);
								
							SQLDBQuery.manageInsertNewTagOnthology(element.getAbsolutePath(), 
															username , MPID, data.getName(), data.getOntoURL());
						}
					}
				}
			}
			
			// do refresh
			if (summaryPane != null ) 
				SummaryPaneRefresher.doRefreshAction( username, MPID, file, summaryPane);			
			else 
				System.out.println ("Summmary Pane is null");
		
			// inform the user
			
			int n = JOptionPane.showConfirmDialog(this, "Tag successfully added. Would you like add more tags ?", 
					"Confirm box", JOptionPane.YES_NO_OPTION);
			
			if ( n == JOptionPane.NO_OPTION) {
				
				parent.setVisible(false);
				// TODO refresh the view pane
				DetailViewAutoRefresh.refreshDetailView_static(detailView, username, file, mainFrame, MPID, baseFolder, clickedFile);
			}
			
		}
		 catch (SQLException e1) {
			e1.printStackTrace();
		}
	}
}
